project(
  'protobuf',
  ['cpp', 'c'],
  version: '25.2',
  license: 'BSD-3-Clause',
  default_options: [
    'warning_level=0',
    #   I was unable to get libprotoc linking as shared library on MINGW, for whatever reason
    # abseil-cpp symbols are sticking out of libprotobuf and are reported as multiple definitions
    #   Linux, Mac and MSVC should work perfectly fine as shared libs
    # If you have time and inspiration, please fix.
    'default_library=static',
    'cpp_std=c++17',
  ],
  meson_version: '>=0.63.0',
)

cc = meson.get_compiler('cpp')

is_shared = (get_option('default_library') != 'static')
is_msvc = (cc.get_argument_syntax() == 'msvc')
should_install = get_option('install')

if is_msvc
  add_project_arguments(
    '-D_CRT_SECURE_NO_WARNINGS',
    '-permissive',
    cc.get_supported_arguments(['-Wno-deprecated-declarations']),
    language: 'cpp',
  )
endif

#   Hey Dev! If you have unresolved `abseil` symbols while linking, when using wrapdb version of the `abseil-cpp`,
# Make sure to build `abseil` using `cpp_std` >= `c++17`
absl_string_view_dep = dependency(
  'absl_string_view',
  default_options: ['cpp_std=c++17'],
)

deps = [
  dependency('absl_base'),
  dependency('absl_cord'),
  dependency('absl_die_if_null'),
  dependency('absl_hash'),
  dependency('absl_log'),
  dependency('absl_log_internal_check_op'),
  dependency('absl_log_internal_message'),
  dependency('absl_numeric'),
  dependency('absl_raw_hash_set'),
  dependency('absl_status'),
  dependency('absl_statusor'),
  dependency('absl_str_format'),
  dependency('absl_strings'),
  dependency('absl_synchronization'),
  absl_string_view_dep,
  dependency('threads'),
  cc.find_library(
    'dbghelp',
    required: host_machine.system() == 'windows',
  ),
]

incdir = include_directories('src')

libutf8_range_src = files(
  'third_party/utf8_range/naive.c',
  'third_party/utf8_range/range-avx2.c',
  'third_party/utf8_range/range-neon.c',
  'third_party/utf8_range/utf8_validity.cc',
)
libutf8_range_args = []
if host_machine.cpu_family() == 'x86_64'
  # range-sse.c is wrapped in #ifdef __x86_64__
  libutf8_range_src += files('third_party/utf8_range/range-sse.c')
  if (meson.get_compiler('cpp').get_argument_syntax() == 'gcc'
  or meson.get_compiler('cpp').get_id() == 'clang-cl'
)
    libutf8_range_args += '-msse4.1'
  elif meson.get_compiler('cpp').get_argument_syntax() == 'msvc'
    libutf8_range_args += '/arch:SSE4.2'
  endif
endif
libutf8_range = static_library(
  'utf8-range',
  sources: libutf8_range_src,
  c_args: libutf8_range_args,
  dependencies: absl_string_view_dep,
)
utf8_range_dep = declare_dependency(
  include_directories: include_directories('third_party/utf8_range'),
  link_with: libutf8_range,
)
deps += utf8_range_dep

libprotobuf_lite_src = files(
  'src/google/protobuf/any_lite.cc',
  'src/google/protobuf/arena.cc',
  'src/google/protobuf/arena_align.cc',
  'src/google/protobuf/arenastring.cc',
  'src/google/protobuf/arenaz_sampler.cc',
  'src/google/protobuf/extension_set.cc',
  'src/google/protobuf/generated_enum_util.cc',
  'src/google/protobuf/generated_message_tctable_lite.cc',
  'src/google/protobuf/generated_message_util.cc',
  'src/google/protobuf/implicit_weak_message.cc',
  'src/google/protobuf/inlined_string_field.cc',
  'src/google/protobuf/io/coded_stream.cc',
  'src/google/protobuf/io/io_win32.cc',
  'src/google/protobuf/io/zero_copy_stream.cc',
  'src/google/protobuf/io/zero_copy_stream_impl.cc',
  'src/google/protobuf/io/zero_copy_stream_impl_lite.cc',
  'src/google/protobuf/map.cc',
  'src/google/protobuf/message_lite.cc',
  'src/google/protobuf/parse_context.cc',
  'src/google/protobuf/port.cc',
  'src/google/protobuf/raw_ptr.cc',
  'src/google/protobuf/repeated_field.cc',
  'src/google/protobuf/repeated_ptr_field.cc',
  'src/google/protobuf/stubs/common.cc',
  'src/google/protobuf/wire_format_lite.cc',
)
api = is_shared ? ['-DPROTOBUF_USE_DLLS'] : []
libprotobuf_lite = library(
  'protobuf-lite',
  libprotobuf_lite_src,
  cpp_args: ['-DLIBPROTOBUF_EXPORTS', api],
  dependencies: deps,
  gnu_symbol_visibility: 'hidden',
  version: meson.project_version(),
  soversion: 25,
  install: should_install,
  include_directories: incdir,
)
imp = is_shared ? ['-DPROTOBUF_USE_DLLS'] : []
protobuf_lite_dep = declare_dependency(
  compile_args: imp,
  link_with: libprotobuf_lite,
  include_directories: incdir,
)

libprotobuf_src = files(
  'src/google/protobuf/any.cc',
  'src/google/protobuf/any.pb.cc',
  'src/google/protobuf/any_lite.cc',
  'src/google/protobuf/api.pb.cc',
  'src/google/protobuf/arena.cc',
  'src/google/protobuf/arena_align.cc',
  'src/google/protobuf/arenastring.cc',
  'src/google/protobuf/arenaz_sampler.cc',
  'src/google/protobuf/compiler/importer.cc',
  'src/google/protobuf/compiler/parser.cc',
  'src/google/protobuf/cpp_features.pb.cc',
  'src/google/protobuf/descriptor.cc',
  'src/google/protobuf/descriptor.pb.cc',
  'src/google/protobuf/descriptor_database.cc',
  'src/google/protobuf/duration.pb.cc',
  'src/google/protobuf/dynamic_message.cc',
  'src/google/protobuf/empty.pb.cc',
  'src/google/protobuf/extension_set.cc',
  'src/google/protobuf/extension_set_heavy.cc',
  'src/google/protobuf/feature_resolver.cc',
  'src/google/protobuf/field_mask.pb.cc',
  'src/google/protobuf/generated_enum_util.cc',
  'src/google/protobuf/generated_message_bases.cc',
  'src/google/protobuf/generated_message_reflection.cc',
  'src/google/protobuf/generated_message_tctable_full.cc',
  'src/google/protobuf/generated_message_tctable_gen.cc',
  'src/google/protobuf/generated_message_tctable_lite.cc',
  'src/google/protobuf/generated_message_util.cc',
  'src/google/protobuf/implicit_weak_message.cc',
  'src/google/protobuf/inlined_string_field.cc',
  'src/google/protobuf/internal_message_util.cc',
  'src/google/protobuf/io/coded_stream.cc',
  'src/google/protobuf/io/gzip_stream.cc',
  'src/google/protobuf/io/io_win32.cc',
  'src/google/protobuf/io/printer.cc',
  'src/google/protobuf/io/strtod.cc',
  'src/google/protobuf/io/tokenizer.cc',
  'src/google/protobuf/io/zero_copy_sink.cc',
  'src/google/protobuf/io/zero_copy_stream.cc',
  'src/google/protobuf/io/zero_copy_stream_impl.cc',
  'src/google/protobuf/io/zero_copy_stream_impl_lite.cc',
  'src/google/protobuf/json/internal/lexer.cc',
  'src/google/protobuf/json/internal/message_path.cc',
  'src/google/protobuf/json/internal/parser.cc',
  'src/google/protobuf/json/internal/unparser.cc',
  'src/google/protobuf/json/internal/untyped_message.cc',
  'src/google/protobuf/json/internal/writer.cc',
  'src/google/protobuf/json/internal/zero_copy_buffered_stream.cc',
  'src/google/protobuf/json/json.cc',
  'src/google/protobuf/map.cc',
  'src/google/protobuf/map_field.cc',
  'src/google/protobuf/message.cc',
  'src/google/protobuf/message_lite.cc',
  'src/google/protobuf/parse_context.cc',
  'src/google/protobuf/port.cc',
  'src/google/protobuf/raw_ptr.cc',
  'src/google/protobuf/reflection_mode.cc',
  'src/google/protobuf/reflection_ops.cc',
  'src/google/protobuf/repeated_field.cc',
  'src/google/protobuf/repeated_ptr_field.cc',
  'src/google/protobuf/service.cc',
  'src/google/protobuf/source_context.pb.cc',
  'src/google/protobuf/struct.pb.cc',
  'src/google/protobuf/stubs/common.cc',
  'src/google/protobuf/text_format.cc',
  'src/google/protobuf/timestamp.pb.cc',
  'src/google/protobuf/type.pb.cc',
  'src/google/protobuf/unknown_field_set.cc',
  'src/google/protobuf/util/delimited_message_util.cc',
  'src/google/protobuf/util/field_comparator.cc',
  'src/google/protobuf/util/field_mask_util.cc',
  'src/google/protobuf/util/message_differencer.cc',
  'src/google/protobuf/util/time_util.cc',
  'src/google/protobuf/util/type_resolver_util.cc',
  'src/google/protobuf/wire_format.cc',
  'src/google/protobuf/wire_format_lite.cc',
  'src/google/protobuf/wrappers.pb.cc',
)
libprotobuf_linker_args = (is_msvc ? [
    '/export:??$MergeFrom@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@RepeatedPtrFieldBase@internal@protobuf@google@@QEAAXAEBV0123@@Z',
  ] : []
)
libprotobuf = library(
  'protobuf',
  sources: libprotobuf_src,
  cpp_args: ['-DLIBPROTOBUF_EXPORTS', api],
  link_args: libprotobuf_linker_args,
  dependencies: [deps],
  gnu_symbol_visibility: 'hidden',
  version: meson.project_version(),
  soversion: 25,
  install: should_install,
  include_directories: incdir,
)
protobuf_dep = declare_dependency(
  compile_args: imp,
  link_with: libprotobuf,
  include_directories: incdir,
  dependencies: deps,
)

libprotoc_src = files(
  'src/google/protobuf/compiler/allowlists/editions.cc',
  'src/google/protobuf/compiler/allowlists/empty_package.cc',
  'src/google/protobuf/compiler/allowlists/open_enum.cc',
  'src/google/protobuf/compiler/allowlists/unused_imports.cc',
  'src/google/protobuf/compiler/allowlists/weak_imports.cc',
  'src/google/protobuf/compiler/code_generator.cc',
  'src/google/protobuf/compiler/command_line_interface.cc',
  'src/google/protobuf/compiler/cpp/enum.cc',
  'src/google/protobuf/compiler/cpp/extension.cc',
  'src/google/protobuf/compiler/cpp/field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/cord_field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/enum_field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/map_field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/message_field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc',
  'src/google/protobuf/compiler/cpp/field_generators/string_field.cc',
  'src/google/protobuf/compiler/cpp/file.cc',
  'src/google/protobuf/compiler/cpp/generator.cc',
  'src/google/protobuf/compiler/cpp/helpers.cc',
  'src/google/protobuf/compiler/cpp/message.cc',
  'src/google/protobuf/compiler/cpp/padding_optimizer.cc',
  'src/google/protobuf/compiler/cpp/parse_function_generator.cc',
  'src/google/protobuf/compiler/cpp/service.cc',
  'src/google/protobuf/compiler/cpp/tracker.cc',
  'src/google/protobuf/compiler/csharp/csharp_doc_comment.cc',
  'src/google/protobuf/compiler/csharp/csharp_enum.cc',
  'src/google/protobuf/compiler/csharp/csharp_enum_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_field_base.cc',
  'src/google/protobuf/compiler/csharp/csharp_generator.cc',
  'src/google/protobuf/compiler/csharp/csharp_helpers.cc',
  'src/google/protobuf/compiler/csharp/csharp_map_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_message.cc',
  'src/google/protobuf/compiler/csharp/csharp_message_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_primitive_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_reflection_class.cc',
  'src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc',
  'src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc',
  'src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc',
  'src/google/protobuf/compiler/csharp/names.cc',
  'src/google/protobuf/compiler/java/context.cc',
  'src/google/protobuf/compiler/java/doc_comment.cc',
  'src/google/protobuf/compiler/java/enum.cc',
  'src/google/protobuf/compiler/java/enum_field.cc',
  'src/google/protobuf/compiler/java/enum_field_lite.cc',
  'src/google/protobuf/compiler/java/enum_lite.cc',
  'src/google/protobuf/compiler/java/extension.cc',
  'src/google/protobuf/compiler/java/extension_lite.cc',
  'src/google/protobuf/compiler/java/field.cc',
  'src/google/protobuf/compiler/java/file.cc',
  'src/google/protobuf/compiler/java/generator.cc',
  'src/google/protobuf/compiler/java/generator_factory.cc',
  'src/google/protobuf/compiler/java/helpers.cc',
  'src/google/protobuf/compiler/java/java_features.pb.cc',
  'src/google/protobuf/compiler/java/kotlin_generator.cc',
  'src/google/protobuf/compiler/java/map_field.cc',
  'src/google/protobuf/compiler/java/map_field_lite.cc',
  'src/google/protobuf/compiler/java/message.cc',
  'src/google/protobuf/compiler/java/message_builder.cc',
  'src/google/protobuf/compiler/java/message_builder_lite.cc',
  'src/google/protobuf/compiler/java/message_field.cc',
  'src/google/protobuf/compiler/java/message_field_lite.cc',
  'src/google/protobuf/compiler/java/message_lite.cc',
  'src/google/protobuf/compiler/java/message_serialization.cc',
  'src/google/protobuf/compiler/java/name_resolver.cc',
  'src/google/protobuf/compiler/java/names.cc',
  'src/google/protobuf/compiler/java/primitive_field.cc',
  'src/google/protobuf/compiler/java/primitive_field_lite.cc',
  'src/google/protobuf/compiler/java/service.cc',
  'src/google/protobuf/compiler/java/shared_code_generator.cc',
  'src/google/protobuf/compiler/java/string_field.cc',
  'src/google/protobuf/compiler/java/string_field_lite.cc',
  'src/google/protobuf/compiler/objectivec/enum.cc',
  'src/google/protobuf/compiler/objectivec/enum_field.cc',
  'src/google/protobuf/compiler/objectivec/extension.cc',
  'src/google/protobuf/compiler/objectivec/field.cc',
  'src/google/protobuf/compiler/objectivec/file.cc',
  'src/google/protobuf/compiler/objectivec/generator.cc',
  'src/google/protobuf/compiler/objectivec/helpers.cc',
  'src/google/protobuf/compiler/objectivec/import_writer.cc',
  'src/google/protobuf/compiler/objectivec/line_consumer.cc',
  'src/google/protobuf/compiler/objectivec/map_field.cc',
  'src/google/protobuf/compiler/objectivec/message.cc',
  'src/google/protobuf/compiler/objectivec/message_field.cc',
  'src/google/protobuf/compiler/objectivec/names.cc',
  'src/google/protobuf/compiler/objectivec/oneof.cc',
  'src/google/protobuf/compiler/objectivec/primitive_field.cc',
  'src/google/protobuf/compiler/objectivec/text_format_decode_data.cc',
  'src/google/protobuf/compiler/php/names.cc',
  'src/google/protobuf/compiler/php/php_generator.cc',
  'src/google/protobuf/compiler/plugin.cc',
  'src/google/protobuf/compiler/plugin.pb.cc',
  'src/google/protobuf/compiler/python/generator.cc',
  'src/google/protobuf/compiler/python/helpers.cc',
  'src/google/protobuf/compiler/python/pyi_generator.cc',
  'src/google/protobuf/compiler/retention.cc',
  'src/google/protobuf/compiler/ruby/ruby_generator.cc',
  'src/google/protobuf/compiler/rust/accessors/accessors.cc',
  'src/google/protobuf/compiler/rust/accessors/singular_message.cc',
  'src/google/protobuf/compiler/rust/accessors/singular_scalar.cc',
  'src/google/protobuf/compiler/rust/accessors/singular_string.cc',
  'src/google/protobuf/compiler/rust/accessors/unsupported_field.cc',
  'src/google/protobuf/compiler/rust/context.cc',
  'src/google/protobuf/compiler/rust/generator.cc',
  'src/google/protobuf/compiler/rust/message.cc',
  'src/google/protobuf/compiler/rust/naming.cc',
  'src/google/protobuf/compiler/rust/oneof.cc',
  'src/google/protobuf/compiler/rust/relative_path.cc',
  'src/google/protobuf/compiler/subprocess.cc',
  'src/google/protobuf/compiler/zip_writer.cc',
)
libprotoc = library(
  'protoc',
  sources: libprotoc_src,
  cpp_args: ['-DLIBPROTOC_EXPORTS', api],
  dependencies: [protobuf_dep, deps],
  version: meson.project_version(),
  soversion: 25,
  install: should_install,
)
protoc_dep = declare_dependency(
  compile_args: imp,
  dependencies: protobuf_dep,
  link_with: libprotoc,
)

if should_install
  pkg = import('pkgconfig')
  pkg.generate(
    libprotobuf_lite,
    description: 'Google\'s Data Interchange Format',
  )
  pkg.generate(
    libprotobuf,
    description: 'Google\'s Data Interchange Format',
  )
  pkg.generate(libprotoc)
endif

subdir('src')
